package pl.nazaweb.utils.restpojomaper;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;

/**
 *
 * @author naza - Marek Kawczyński
 */
public abstract class ReflectionHelper {

    private Class<?> paramatrizedClass;

    protected Object newPojoInstance(String methodName) {
        try {
            Class<?> c = getMapAsPojoAnnoatationClass(methodName);
            return c.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Nie można utworzyć instancji pojo. Sprawdź czy istnieje konsruktor bezargumenotwy.");
            return null;
        }
    }

    public String getMapAsMapValueMethod(String methodName) {
        try {
            return getMapAsMapAnnoatation(methodName).valueProperty();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Nie można pobrać metody key dla adnotacji mapowania jako mapa");
            return null;
        }
    }

    public String getMapAsMapKeyMethod(String methodName) {
        try {
            return getMapAsMapAnnoatation(methodName).keyProperty();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Nie można pobrać metody key dla adnotacji mapowania jako mapa");
            return null;
        }
    }

    private Class<?> getMapAsPojoAnnoatationClass(String methodName) throws NoSuchMethodException {
        Method m = this.getMethod(methodName);
        MapAsPojo annotattion = m.getAnnotation(MapAsPojo.class);
        return annotattion.value();
    }

    private MapAsMap getMapAsMapAnnoatation(String methodName) throws NoSuchMethodException {
        Method m = this.getMethod(methodName);
        return m.getAnnotation(MapAsMap.class);
    }

    protected Class<?> getParameterizedClass() {
        if (paramatrizedClass == null) {
            ParameterizedType paramatrizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
            paramatrizedClass = (Class<?>) paramatrizedType.getActualTypeArguments()[0];
        }
        return paramatrizedClass;
    }

    protected boolean hasMethodHaveMapAsPojoAnnotation(String methodName) {
        return hasMapAsPojoAnnotation(getMethodWithTryCatch(methodName));
    }

    protected boolean hasMethodHaveMapAsMapAnnotation(String methodName) {
        return hasMapAsMapAnnotation(getMethodWithTryCatch(methodName));
    }

    private Method getMethodWithTryCatch(String methodName) {
        try {
            return getMethod(methodName);

        } catch (Exception e) {
            return null;
        }
    }

    private Method getMethod(String name) throws NoSuchMethodException {
        for (Method m : this.getClass().getDeclaredMethods()) {
            if (m.getName().toLowerCase().equals(name.toLowerCase())) {
                return m;
            }
        }
        return null;
    }

    private boolean hasMapAsPojoAnnotation(Method method) {
        for (Annotation annotation : method.getAnnotations()) {
            if (annotation instanceof MapAsPojo) {
                return true;
            }
        }
        return false;
    }

    protected boolean hasMapAsMapAnnotation(Method method) {
        for (Annotation annotation : method.getAnnotations()) {
            if (annotation instanceof MapAsMap) {
                return true;
            }
        }
        return false;
    }
}
